Honor resource command confirmations in CLI#16669
Honor resource command confirmations in CLI#16669maddymontaquila wants to merge 1 commit intomainfrom
Conversation
Flow resource command confirmation metadata through the backchannel and prompt before executing confirmed commands from aspire resource. Add --non-interactive as an explicit confirmation override for automation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 16669Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 16669" |
There was a problem hiding this comment.
Pull request overview
This PR makes aspire resource <resource> <command> honor per-command confirmation metadata emitted by the AppHost. The CLI now reads a ConfirmationMessage from resource snapshots, prompts the user before executing confirmed commands, and introduces a --non-interactive automation override intended to accept confirmations without prompting.
Changes:
- Flow a new
ConfirmationMessagefield from Hosting backchannel snapshots through the CLI resource JSON model. - Add confirmation gating to
ResourceCommandHelperprior to invoking backchannel command execution. - Add/extend CLI unit tests, update skill guidance docs, and update localization resources for the new option description.
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Aspire.Cli.Tests/TestServices/TestAppHostAuxiliaryBackchannel.cs | Adds handler/call-count support to validate whether commands were executed in tests. |
| tests/Aspire.Cli.Tests/Commands/ResourceCommandTests.cs | Adds a parsing/invocation test for --non-interactive on resource. |
| tests/Aspire.Cli.Tests/Commands/ResourceCommandHelperTests.cs | Adds coverage for confirmed/declined/non-interactive confirmation flows. |
| tests/Aspire.Cli.Tests/Backchannel/ResourceSnapshotMapperTests.cs | Verifies ConfirmationMessage is mapped into CLI resource JSON. |
| src/Shared/Model/Serialization/ResourceJson.cs | Extends ResourceCommandJson with ConfirmationMessage. |
| src/Aspire.Hosting/Backchannel/BackchannelDataTypes.cs | Extends ResourceSnapshotCommand with ConfirmationMessage. |
| src/Aspire.Hosting/Backchannel/AuxiliaryBackchannelRpcTarget.cs | Flows ConfirmationMessage into snapshot RPC payloads. |
| src/Aspire.Cli/Commands/ResourceCommandHelper.cs | Adds confirmation lookup + prompt prior to executing resource commands. |
| src/Aspire.Cli/Commands/ResourceCommand.cs | Adds --non-interactive option and passes a confirmation binding to helper methods. |
| src/Aspire.Cli/Backchannel/ResourceSnapshotMapper.cs | Maps ConfirmationMessage into ResourceCommandJson. |
| src/Aspire.Cli/Resources/ResourceCommandStrings.resx | Adds localized string for --non-interactive description. |
| src/Aspire.Cli/Resources/ResourceCommandStrings.Designer.cs | Adds strongly-typed accessor for the new resource string. |
| src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.cs.xlf | Adds NonInteractiveOptionDescription translation unit. |
| src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.de.xlf | Adds NonInteractiveOptionDescription translation unit. |
| src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.es.xlf | Adds NonInteractiveOptionDescription translation unit. |
| src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.fr.xlf | Adds NonInteractiveOptionDescription translation unit. |
| src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.it.xlf | Adds NonInteractiveOptionDescription translation unit. |
| src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ja.xlf | Adds NonInteractiveOptionDescription translation unit. |
| src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ko.xlf | Adds NonInteractiveOptionDescription translation unit. |
| src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.pl.xlf | Adds NonInteractiveOptionDescription translation unit. |
| src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.pt-BR.xlf | Adds NonInteractiveOptionDescription translation unit. |
| src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ru.xlf | Adds NonInteractiveOptionDescription translation unit. |
| src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.tr.xlf | Adds NonInteractiveOptionDescription translation unit. |
| src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.zh-Hans.xlf | Adds NonInteractiveOptionDescription translation unit. |
| src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.zh-Hant.xlf | Adds NonInteractiveOptionDescription translation unit. |
| .agents/skills/aspire/references/resource-management.md | Updates agent guidance to mention confirmation prompts and --non-interactive. |
Files not reviewed (1)
- src/Aspire.Cli/Resources/ResourceCommandStrings.Designer.cs: Language not supported
| private static readonly Option<bool> s_nonInteractiveOption = new("--non-interactive") | ||
| { | ||
| Description = ResourceCommandStrings.NonInteractiveOptionDescription | ||
| }; |
There was a problem hiding this comment.
--non-interactive is already defined as a recursive global option on RootCommand (see RootCommand.NonInteractiveOption). Adding a second Option<bool>("--non-interactive") on ResourceCommand can create ambiguous binding depending on where the flag appears (e.g. aspire --non-interactive resource ... may bind to the root option while this code reads the resource-scoped option), which would break the intended auto-confirm behavior in non-interactive runs. Consider removing the resource-scoped option and instead using RootCommand.NonInteractiveOption for PromptBinding.Create(...) (or introduce a distinct option name for the resource-confirmation override).
| private static readonly Option<bool> s_nonInteractiveOption = new("--non-interactive") | |
| { | |
| Description = ResourceCommandStrings.NonInteractiveOptionDescription | |
| }; | |
| private static readonly Option<bool> s_nonInteractiveOption = RootCommand.NonInteractiveOption; |
| return null; | ||
| } | ||
|
|
||
| var command = resources[0].Commands.FirstOrDefault(c => string.Equals(c.Name, commandName, StringComparison.OrdinalIgnoreCase)); |
There was a problem hiding this comment.
GetConfirmationMessageAsync looks up the command by name but doesn't consider the command state. If a command exists but is Disabled/Hidden, the CLI will still prompt for confirmation and then the backchannel execution will fail anyway, which is a confusing flow. Consider filtering to State == "Enabled" (or whatever enabled value is expected) before prompting, or skipping confirmation when the command isn't executable.
| var command = resources[0].Commands.FirstOrDefault(c => string.Equals(c.Name, commandName, StringComparison.OrdinalIgnoreCase)); | |
| var command = resources[0].Commands.FirstOrDefault(c => | |
| string.Equals(c.Name, commandName, StringComparison.OrdinalIgnoreCase) && | |
| string.Equals(c.State, "Enabled", StringComparison.OrdinalIgnoreCase)); |
|
🎬 CLI E2E Test Recordings — 76 recordings uploaded (commit View all recordings
📹 Recordings uploaded automatically from CI run #25229282820 |
Description
Make
aspire resource <resource> <command>honor resource command confirmation messages before executing commands. The CLI now readsConfirmationMessagefrom resource snapshots, prompts before invoking commands that require confirmation, and supports--non-interactiveas an explicit automation override that accepts the confirmation without prompting.This also flows confirmation metadata through the AppHost backchannel and CLI resource JSON model, updates the generated Aspire agent skill guidance, and adds focused CLI tests for confirmed, declined, and non-interactive command execution.
Validation:
dotnet test --project tests\Aspire.Cli.Tests\Aspire.Cli.Tests.csproj --no-launch-profile -- --filter-class "*.ResourceCommandHelperTests" --filter-class "*.ResourceCommandTests" --filter-class "*.ResourceSnapshotMapperTests" --filter-class "*.AgentInitCommandTests" --filter-class "*.CommonAgentApplicatorsTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"dotnet build /t:UpdateXlf src\Aspire.Cli\Aspire.Cli.csprojFixes # (issue)
Checklist
<remarks />and<code />elements on your triple slash comments?aspire.devissue: